package com.wsoft.bpm.service;

import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.wsoft.bpm.entity.ActProcessMappingEntity;
import com.wsoft.bpm.enums.ApproveStatus;
import com.wsoft.bpm.mapper.BpmActivitiMapper;
import com.wsoft.bpm.service.impl.DefaultActivitiCallAbleImpl;
import com.wsoft.core.exception.Asserts;

import java.util.Map;

/**
 * 工作流回调接口
 *
 * @Author zhonglj
 * @Date 2024-10-09 8:52
 */
public interface ActivitiCallAble {
    /**
     * 完成-工作流自动回调
     *
     * @param processKey
     * @param processInstanceId 流程实例id
     * @param businessKey
     * @author zhonglj
     * @date 2024-10-09 9:01
     **/
    default void callComplete(String processKey, String processInstanceId, String businessKey) {
        updateApproveStatus(processInstanceId, businessKey, ApproveStatus.APPROVED);
        complete(processKey, processInstanceId, businessKey);
    }


    /**
     * 完成-业务逻辑覆盖
     *
     * @param processKey
     * @param processInstanceId 流程实例id
     * @param businessKey
     * @author zhonglj
     * @date 2024-10-09 9:01
     **/
    default void complete(String processKey, String processInstanceId, String businessKey) {
    }


    /**
     * 退回至提交人-工作流自动回调
     *
     * @param processKey
     * @param processInstanceId 流程实例id
     * @param businessKey
     * @author zhonglj
     * @date 2024-10-09 9:01
     **/
    default void callBack(String processKey, String processInstanceId, String businessKey) {
        updateApproveStatus(processInstanceId, businessKey, ApproveStatus.BACK);
        back(processKey, processInstanceId, businessKey);
    }

    /**
     * 退回至提交人-业务逻辑覆盖
     *
     * @param processKey
     * @param processInstanceId 流程实例id
     * @param businessKey
     * @author zhonglj
     * @date 2024-10-09 9:01
     **/
    default void back(String processKey, String processInstanceId, String businessKey) {
    }

    /**
     * 驳回至提交人-工作流自动回调
     *
     * @param processKey
     * @param processInstanceId 流程实例id
     * @param businessKey
     * @author zhonglj
     * @date 2024-10-09 9:03
     **/
    default void callReject(String processKey, String processInstanceId, String businessKey) {
        updateApproveStatus(processInstanceId, businessKey, ApproveStatus.REJECT);
        reject(processKey, processInstanceId, businessKey);
    }

    /**
     * 驳回至提交人-业务逻辑覆盖
     *
     * @param processKey
     * @param processInstanceId 流程实例id
     * @param businessKey
     * @author zhonglj
     * @date 2024-10-09 9:03
     **/
    default void reject(String processKey, String processInstanceId, String businessKey) {
    }

    /**
     * 绑定流程定义码,默认使用DefaultActivitiCallAbleImpl
     *
     * @param
     * @return com.wsoft.bpm.enums.BpmProcessDef
     * @author zhonglj
     * @date 2024-10-09 9:53
     **/
    default String getProcessDefKey() {
        return StrUtil.EMPTY;
    }

    /**
     * 返回匹配的处理服务
     *
     * @param key 工作流唯一编码
     * @return com.wsoft.bpm.service.ActivitiCallAble
     * @author zhonglj
     * @date 2024-10-09 9:09
     **/
    static ActivitiCallAble findCallService(String key) {
        Map<String, ActivitiCallAble> beansOfType = SpringUtil.getBeansOfType(ActivitiCallAble.class);
        // 遍历并调用每个 Bean 的 call 方法
        for (ActivitiCallAble callAble : beansOfType.values()) {
            if (callAble.getProcessDefKey().equals(key)) {
                return callAble;
            }
        }

        return SpringUtil.getBean(DefaultActivitiCallAbleImpl.class);
    }

    /**
     * 更新数据库状态
     *
     * @param processInstanceId
     * @param businessKey
     * @param status
     * @return int
     * @author zhonglj
     * @date 2024-10-09 10:20
     **/
    static int updateApproveStatus(String processInstanceId, String businessKey, ApproveStatus status) {
        BpmActivitiMapper mapper = SpringUtil.getBean(BpmActivitiMapper.class);
        IActProcessMappingService mappingService = SpringUtil.getBean(IActProcessMappingService.class);
        ActProcessMappingEntity processMapping = mappingService.getOne(Wrappers.lambdaQuery(ActProcessMappingEntity.class)
                .eq(ActProcessMappingEntity::getProcessInstantId, processInstanceId)
        );
        if (processMapping == null) {
            Asserts.fail("[bpm.process.error.updateApproveStatus.none.processMapping]");
        }

        return mapper.updateApproveStatus(
                processMapping.getTableName(),
                processMapping.getStatusColumn(),
                status.getValue(),
                processMapping.getBusinessKeyColumn(),
                businessKey
        );
    }
}
